/** @file batch.h
	@brief Geometry batch */

#ifndef G3_BATCH_H
#define G3_BATCH_H

#include "log.h"

#include "geompointer.h"
#include "math/m_bounding.h"

#include <string>
#include <SDL/SDL.h>

/** Default maximum batch depth */
#define DEF_MAX_BATCH_DEPTH     1000

namespace G3 {

/** Maximum batch depth */
extern double Maximum_Batch_Depth;

/** @class BATCH
	@brief Geometry batch class*/
class BATCH {
    public:
        BATCH ();
        BATCH (const BATCH &b);
        ~BATCH ();

        /** Bounding box of the batch */
        G3::AABB3F BBox;
        /** Material ID of the batch */
        int matID;
        /** Index offset */
        int indexStart;
        /** Number of triangles to render */
        int numElements;

        /** OpenGL Display List ID (only used if VBO-s are disabled) */
        int display_list_id;

        /** @struct KEY
            @brief An unpacked key structure */
        struct KEY {
            /**
                @brief Constructor that initializes the members
            */
            KEY ();

            /** Fullscreen layers */
            enum FSCR_LAYER {
                FSCRL_GAME = 0,
                FSCRL_EFFECTS = 1,
                FSCRL_HUD = 2
            };

            /** Viewport layers */
            enum VPORT_LAYER {
                VPORTL_SKYBOX = 0,
                VPORTL_WORLD = 1,
                VPORTL_EFFECTS = 2,
                VPORTL_HUD = 3
            };

            /** Translucency types */
            enum TRANS_TYPE {
                TRANS_OPAQUE = 0,
                TRANS_ADD = 1,
                TRANS_SUB = 2,
                TRANS_MUL = 3
            };

            /** Special commands \todo Add some */
            enum COMMAND {
                CMD_VBO_SWAP = 0
            };

            /** 2-bit fullscreen layer \see FSCR_LAYER */
            byte fscr_layer;
            /** 3-bit viewport number */
            byte vport;
            /** 3-bit viewport layer \see VPORT_LAYER */
            byte vport_layer;
            /** 2-bit translucency type \see TRANS_TYPE */
            byte trans_type;
            /** 1-bit command flag */
            bool cmd;
            /** 21-bit material id */
            uint mat_id;
            /** 8-bit pass number \todo 8 could be too much ? */
            byte pass;
            /** 24-bit depth */
            uint depth;
            /** 8-bit sequence number */
            byte sequence;
            /** 45-bit command \see COMMAND */
            unsigned long long command;

            /**
                @brief Assignment operator
                @param[in] k Reference to the key to be copied
                @return Reference to the fresh copy
            */
            KEY& operator= (const KEY &k);
            /**
                @brief Comparison operator
                @param[in] k Reference to the key to be compared to this one
                @return True if both are equal and false, if only one is equal :D
            */
            bool operator== (const KEY &k);

            /**
                @brief Dumps the key into the log
                @param[in] log Pointer to the log
            */
            void Dump (G3::LOG *log);
        };

        /** The long long packed key */
        long long key;

        /** Last time this batch was rendered */
        long last_render;

        BATCH& operator= (const BATCH &b);

        /**
            @brief Packs the key
            @param[in] k Reference to the unpacked key structure
            @return The packed key
        */
        long long packKey (const KEY &k);

        /**
            @brief Restores the unpacked key structure from a packed key
            @param[in] k Reference to the long long key
            @return The unpacked key structure
        */
        KEY unpackKey (const long long &k);

        /**
            @brief Generates a key for this batch
            @param[in] pos Reference to the observer position (for depth calculation)
            @return The long long key
        */
        long long genKey (const G3::VEC3F &pos);

        /**
            @brief Splits the key in 2 halves
            @param[out] msl Reference to the most significant long
            @param[out] lsl Reference to the less significant long
        */
        void splitKey (long &msl, long &lsl);

        /**
            @brief Returns the key as a string
            @return The key as a string
        */
        std::string keyToString ();

        /**
            @brief Draws this batch
            @param[in] gp Pointer to a geometry pointer (only needed if the renderer is running without any optimizations) \see O_NONE
        */
        void render (G3::GEOM_POINTER *gp = NULL);
};

}

#endif // G3_BATCH_H
